﻿using System;
using Game2DFramework.Collision;
using MechGame.Data;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace MechGame.Game.Leveling
{
    class Tilemap
    {
        private const int TileSize = 32;
        
        private readonly int[] _groundData;
        private readonly int[] _fringeData;
        private readonly int[] _collisionData;
        private readonly int _width;
        private readonly int _height;
        private readonly Texture2D _tileset;
        private readonly int _tilesX;

        public Tilemap(ContentManager content, string tilemapAsset)
        {
            var data = content.Load<TilemapData>(tilemapAsset);
            _width = data.Width;
            _height = data.Height;
            _tileset = content.Load<Texture2D>(data.TilesetAsset);
            _tilesX = _tileset.Width/TileSize;

            var itemLength = _width*_height;
            _groundData = new int[itemLength];
            _fringeData = new int[itemLength];
            _collisionData = new int[itemLength];
            Array.Copy(data.GroundLayer, _groundData, itemLength);
            Array.Copy(data.FringeLayer, _fringeData, itemLength);
            Array.Copy(data.CollisionLayer, _collisionData, itemLength);
        }

        public Vector2 GetWorldFromTilePositionCentered(Point tilePosition)
        {
            return GetWorldFromTilePosition(tilePosition) + new Vector2(TileSize)*0.5f;
        }

        public Vector2 GetWorldFromTilePosition(Point tilePosition)
        {
            return new Vector2(tilePosition.X * TileSize, tilePosition.Y * TileSize);
        }

        public Point GetTilePositionFromWorld(Vector2 world)
        {
            return new Point((int)Math.Floor(world.X / 32), (int)Math.Floor(world.Y / 32));
        }

        public Rectangle WorldBounds { get { return new Rectangle(0,0, _width*TileSize, _height*TileSize); } }

        public bool CollidesWith(Circle circle)
        {
            var minPoint = GetTilePositionFromWorld(new Vector2(circle.X, circle.Y) - new Vector2(circle.Radius));
            var maxPoint = GetTilePositionFromWorld(new Vector2(circle.X, circle.Y) + new Vector2(circle.Radius));

            for (var y = minPoint.Y; y <= maxPoint.Y; y++)
            {
                for (var x = minPoint.X; x <= maxPoint.X; x++)
                {
                    if (_collisionData[y * _width + x] == 0) continue;

                    var pos = GetWorldFromTilePosition(new Point(x, y));
                    var localRect = new Rectangle((int) pos.X, (int) pos.Y, TileSize, TileSize);
                    if (circle.Intersects(localRect)) return true;
                }
            }

            return false;
        }

        public void Update(float elapsed)
        {
            
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            DrawLayer(spriteBatch, _groundData);
            DrawLayer(spriteBatch, _fringeData);
        }

        private void DrawLayer(SpriteBatch spriteBatch, int[] data)
        {
            for (var x = 0; x < _width; ++x)
            {
                for (var y = 0; y < _height; ++y)
                {
                    var tileIndex = data[y*_width + x];
                    if (tileIndex == 0) continue;
                    tileIndex--;
                    var position = new Vector2(x*TileSize, y*TileSize);
                    var sourceRectangle = new Rectangle((tileIndex % _tilesX) * TileSize, (tileIndex / _tilesX) * TileSize, TileSize, TileSize);

                    spriteBatch.Draw(_tileset, position, sourceRectangle, Color.White);
                }
            }
        }
    }
}
